﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

using System.IO;
using System.Xml;
using Microsoft.WindowsAzure.ServiceRuntime;
using Commons = NougakudoCompanion.Commons;
using NougakudoCompanion.Utils;

namespace NougakudoCompanion.Commons
{
    public partial class Runtime
    {
        bool isLoaded = false;

        internal static Tuple<bool, Runtime> CreateInstance()
        {
            Runtime runtime = new Runtime();
            runtime.SetupForController();
            bool ret = false;
            try
            {
                ret = runtime.GetAzureEnvironment();

                ret = runtime.LoadConfiguration(false);
                if (ret)
                {
                    runtime.isLoaded = true;
                    return new Tuple<bool,Runtime>(true, runtime);

                }
            }
            catch (Exception e)
            {
                Logging.Write("Runtime:Initialize error : " + e.Message );
            }
            // default settings
            runtime.environment.Name = RoleEnvironment.GetConfigurationSettingValue(Constants.AZURE_CONFIG_NAME);
            runtime.environment.Version = "1.0.5";
            runtime.applications = new Dictionary<string, Commons.Application>();
            runtime.isLoaded = false;
            return new Tuple<bool, Runtime>(ret, runtime);

        }

        void SetupForController()
        {
            this.GetAzureEnvironment = GetAzureEnvironmentForWebRole;
            this.LoadConfiguration = LoadConfigurationForWebRole;
        }

        public bool IsLoade { get { return isLoaded; } }

        bool GetAzureEnvironmentForWebRole()
        {
            try
            {
                var workingfolder = RoleEnvironment.GetConfigurationSettingValue(Constants.AZURE_CONFIG_WORKING_FOLDER);
                var runtimefolder = Path.Combine(RoleEnvironment.GetLocalResource(Commons.Constants.RESOURCE_RUNTIME).RootPath, workingfolder);
                var appfolder = Path.Combine(RoleEnvironment.GetLocalResource(Commons.Constants.RESOURCE_APPLICATION).RootPath, workingfolder);
                var downfolder = Path.Combine(RoleEnvironment.GetLocalResource(Commons.Constants.RESOURCE_DOWNLOAD).RootPath, workingfolder);

                var name = RoleEnvironment.GetConfigurationSettingValue(Commons.Constants.AZURE_CONFIG_NAME);
                var rolefolder = System.Environment.ExpandEnvironmentVariables("%RoleRoot%\\approot");
                var instanceid = RoleEnvironment.CurrentRoleInstance.Id;
                var interval = int.Parse(RoleEnvironment.GetConfigurationSettingValue(Commons.Constants.AZURE_CONFIG_INTERVAL));
                var account = RoleEnvironment.GetConfigurationSettingValue(Commons.Constants.AZURE_CONFIG_ACCOUNT);
                var sharedKey = RoleEnvironment.GetConfigurationSettingValue(Commons.Constants.AZURE_CONFIG_SHAREDKEY);
                var container = RoleEnvironment.GetConfigurationSettingValue(Commons.Constants.AZURE_CONFIG_CONTAINER);
                //var developmentfabric = bool.Parse(RoleEnvironment.GetConfigurationSettingValue(Commons.Constants.AZURE_CONFIG_DEVLOPMENTFABRIC));
                var developmentfabric = RoleEnvironment.IsEmulated;     // Add for Azure SDK 1.5.
                var virtualHost = RoleEnvironment.GetConfigurationSettingValue(Commons.Constants.AZURE_CONFIG_VIRTUALHOST); // Add for NougakuDo 1.1.0 above.

                var tempfolder = Path.Combine(RoleEnvironment.GetLocalResource(Commons.Constants.RESOURCE_TEMP).RootPath, workingfolder);    // Add temp folder;

                environment = new Commons.Environment
                {
                    RuntimeFolder = runtimefolder,
                    ApplicationFolder = appfolder,
                    DownloadFolder = downfolder,
                    Name = name,
                    RoleRoot = rolefolder,
                    RoleInstanceID = instanceid,
                    Interval = interval,
                    Account = account,
                    SharedKey = sharedKey,
                    BlobContainer = container,
                    UseDevelopmentFabric = developmentfabric,
                    VirtualHost = virtualHost,   // Add for NougakuDo 1.1.0 above.
                    TempFolder = tempfolder
                };
                return true;
            }
            catch (Exception e)
            {
                throw e;
            }
        }


        /// <summary>
        /// Load configuration.xml, then load newconfiguration.xml. 
        /// </summary>
        /// <returns></returns>
        internal bool LoadConfigurationForWebRole(bool recovery = false)
        {
            var config = CheckConfiguration();
            if (config == "")
            {
                return false;
            }

            var ret = GetConfiguration(config);
            if (ret.Item1 == "")
            {
                return false;
            }
            environment.Version = ret.Item1;
            applications = ret.Item2;

            return true;
        }


        /// <summary>
        /// If not exsist configuration file, download it from blob. 
        /// </summary>
        /// <returns>success</returns>
        string CheckConfiguration()
        {
            var download = Path.Combine(environment.DownloadFolder, Commons.Constants.CONFIGURATION);
            if (File.Exists(download))
                return download;
            var running = Path.Combine(environment.RuntimeFolder, Commons.Constants.CONFIGURATION);
            if (File.Exists(running))
            {
                try
                {
                    File.Copy(running, download);
                    return download;
                }
                catch (Exception e)
                {
                    Logging.Write("CheckConfiguration Error :" + e.Message);
                }
            }

            if (GetDownload(download))
                return download;
            return "";
        }

        bool GetDownload(string download)
        {
            var ret = Commons.BlobStorageHelper.DownloadBlob(environment, Commons.Constants.CONFIGURATION, download);
            if (!ret.Item1)
            {
                FileDelete(download);
            }
            return ret.Item1;

        }

        internal Tuple<bool, string> MakeConfiguration()
        {
            var doc = new XmlDocument();
            var rootNode = doc.CreateElement("configuration");
            var runtimeNode = doc.CreateElement("runtime");

            var nameNode = doc.CreateElement("name");
            nameNode.InnerText = environment.Name;
            var versionAtt = doc.CreateAttribute("version");
            versionAtt.Value = environment.Version;
            nameNode.Attributes.Append(versionAtt);
            runtimeNode.AppendChild(nameNode);

            rootNode.AppendChild(runtimeNode);
            rootNode.AppendChild(CreateApplicationElement(doc));

            var decNode = doc.CreateXmlDeclaration("1.0", "utf-8", "yes");
            doc.AppendChild(rootNode);
            doc.InsertBefore(decNode, rootNode);

            try
            {
                var file = Path.Combine(environment.DownloadFolder, Commons.Constants.CONFIGURATION);
                doc.Save(file);

                var ret = Commons.BlobStorageHelper.UploadBlob(environment, Commons.Constants.CONFIGURATION, file);
                return ret;
            }
            catch (Exception e)
            {
                Logging.Write("MakeConfiguration Error :" + e.Message);
                return new Tuple<bool, string>(false, e.Message);
            }

        }

        XmlElement CreateApplicationElement(XmlDocument doc)
        {
            var applicationsNode = doc.CreateElement("applications");
            foreach (var app in applications.Keys)
            {
                var applicationNode = doc.CreateElement("application");
                var nameNode = doc.CreateElement("name");
                nameNode.InnerText = applications[app].Name;
                var versionAtt = doc.CreateAttribute("version");
                versionAtt.Value = applications[app].Version;
                nameNode.Attributes.Append(versionAtt);
                applicationNode.AppendChild(nameNode);

                var processNode = doc.CreateElement("process");
                processNode.InnerText = applications[app].NumOfProcess.ToString();
                applicationNode.AppendChild(processNode);

                var environmentNode = doc.CreateElement("environment");
                environmentNode.InnerText = applications[app].Environment;
                applicationNode.AppendChild(environmentNode);

                // Add for NougakuDo 1.1.0 above.
                var virtualHostNode = doc.CreateElement("virtualhost");
                virtualHostNode.InnerText = applications[app].VirtualHost.ToString().ToLower();
                applicationNode.AppendChild(virtualHostNode);

                applicationsNode.AppendChild(applicationNode);
            }
            return applicationsNode;
        }

    }

}